package beusoft.ccjk.com.calculator;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by CCJK on 2017/12/10.
 */

public class Calculator {

    private static String Regex = "[+-/*/()]";
    private String expression;
    /**
     * 中缀表达式拆分后的值的队列
     */
    private Queue<String> infixExpressionValues = new LinkedList<>();
    /**
     * 后缀表达式拆分后的值的队列
     */
    private Queue<String> postfixExpressionValues = new LinkedList<>();

    /**
     * 符号栈
     */
    private Stack<String> operatorStack = new Stack<>();


    private Pattern pattern;

    /**
     * 符号的优先级,数字越大优先级越高
     */
    private static HashMap<String, Integer> priorityMap = new HashMap<>();

    static {
        priorityMap.put("+", 0);
        priorityMap.put("-", 0);
        priorityMap.put("*", 1);
        priorityMap.put("/", 1);
        priorityMap.put("(", 2);
        priorityMap.put(")", 2);
    }


    public Calculator(String expression) {
        this.expression = expression;
        if (checkExpression()) {
            fixExpression();
            initInfixExpressionValues();
            infixExpressionToPostfixExpression();

            calculate();
        } else throw new RuntimeException("无效的表达式");
    }

    private void calculate() {
        Stack<Double> doubleStack = new Stack<>();
        while (!postfixExpressionValues.isEmpty()) {
            String s = postfixExpressionValues.poll();
            if (isOperator(s)) {
                double a = doubleStack.pop();
                double b = doubleStack.pop();
                if (s.equals("+")) {
                    doubleStack.push(b+a);
                } else if (s.equals("-")) {
                    doubleStack.push( b-a);
                } else if (s.equals("*")) {
                    doubleStack.push(b*a);
                } else if (s.equals("/")) {
                    doubleStack.push( b/a);
                }
            } else {
                doubleStack.push((double) Integer.parseInt(s));
            }
        }
        println(doubleStack);
    }

    /**
     * 将中缀表达式转换成后缀表达式
     * a+b*c --> abc*+
     * <p>
     * 1*(2+3)+2 -->123+*2+
     */
    private void infixExpressionToPostfixExpression() {
        while (!infixExpressionValues.isEmpty()) {
            dumps();
            String s = infixExpressionValues.poll();
            if (isOperator(s)) {
                if (s.equals("(")) {
                    operatorStack.push(s);
                } else if (s.equals(")")) {
                    while (!operatorStack.isEmpty()) {//如果操作符栈不为空
                        String op = operatorStack.pop();
                        if (op.equals(")")) {//如果栈里的符号是)
                            break;
                        } else {
                            postfixExpressionValues.offer(op);
                        }
                    }
                } else {
                    if (operatorStack.isEmpty()) {
                        operatorStack.push(s);
                    } else {
                        String opTop = operatorStack.pop();
                        if (opTop.equals("(")) {
                            operatorStack.push(s);
                        } else {//2+2*6  3*(3-1)
                            if (priorityMap.get(opTop) < priorityMap.get(s)) {
                                operatorStack.push(opTop);
                                operatorStack.push(s);
                            } else {
                                postfixExpressionValues.offer(opTop);
                                operatorStack.push(s);
                            }
                        }
                    }
                }
            } else {
                postfixExpressionValues.offer(s);
            }
        }
        while (!operatorStack.isEmpty()) {
            postfixExpressionValues.offer(operatorStack.pop());
        }
        dumps();


    }

    private void dumps() {
        println("///////////////////////////////////////////////////////////");
        println("infix: " + infixExpressionValues);
        println("postFix: " + postfixExpressionValues);
        println("stack: " + operatorStack);


    }


    /**
     * 获取操作符栈中最新的符号的优先级
     *
     * @return
     */
    private int getOperatorStackLatestPriority() {
        if (operatorStack.isEmpty()) {
            return -1;
        }
        return priorityMap.get(operatorStack.peek());
    }

    private boolean isOperator(String s) {
        return pattern.matcher(s).find();
    }

    /**
     * 处理开头不是数字的字符串,和结尾不是数字的情况
     */
    private void fixExpression() {
        char firstChar = expression.charAt(0);
        if (firstChar == '+' || firstChar == '-') {
            expression = "0" + expression;
        } else if (firstChar == '(') {
            expression = "0+" + expression;
        }
        char lastChar = expression.charAt(expression.length() - 1);
        if (lastChar == ')') {
            expression = expression + "+0";
        }
    }

    /**
     * 检查表达式是否有效
     *
     * @return
     */
    private boolean checkExpression() {

        return true;
    }

    private void initInfixExpressionValues() {
        pattern = Pattern.compile(Regex);
        Matcher matcher = pattern.matcher(expression);
        int lastIndex = 0;
        String matchString;
        while (matcher.find()) {
            int start = matcher.start();
            int end = matcher.end();
            matchString = expression.substring(start, end);
            if (lastIndex >= start) {//1+2-3*(3+3)  *( 连续出现时就会到这里
                infixExpressionValues.offer(matchString);
            } else {
                infixExpressionValues.offer(expression.substring(lastIndex, start).trim());//添加数字
                infixExpressionValues.offer(matchString);//添加符号
            }
            lastIndex = end;
        }
        if (lastIndex != expression.length()) {//说明最后还有一个数字
            infixExpressionValues.offer(expression.substring(lastIndex, expression.length()).trim());//添加数字
        }

        print(infixExpressionValues);
    }


    private void println(Object o) {
        System.out.println(o);
    }

    private void print(Object o) {
        System.out.print(" " + o);
    }
}
